package com.example.mysql.mybaits;

import org.apache.ibatis.annotations.*;
import org.springframework.stereotype.Component;
import org.springframework.util.StringUtils;
import java.lang.reflect.Field;
import java.lang.reflect.InvocationTargetException;
import java.lang.reflect.Method;
import java.util.Collections;
import java.util.List;
import java.util.Map;
import java.util.stream.Collectors;

/**
 * @author ZhenWuWang
 */
@Mapper
@Component(value = "myBaitsMapper")
public interface MyBaitsMapper
{
    @SelectProvider(type = BaseSqlProvider.class, method = "select")
    List<Map<String, Object>> select(@Param("tableName") String tableName,
                                     @Param("whereCase") String whereCase);

    @SelectProvider(type = BaseSqlProvider.class, method = "select")
    List<Map<String, Object>> selectByColumns(@Param("tableName") String tableName, @Param("columns") List<String> columns,
                                              @Param("whereCase") String whereCase);

    @InsertProvider(type = BaseSqlProvider.class, method = "insert")
    Integer insert(@Param("tableName") String tableName, @Param("data") Object data);

    @UpdateProvider(type = BaseSqlProvider.class, method = "update")
    int update(@Param("tableName") String tableName, @Param("data") Object data);

//    @DeleteProvider(type = BaseSqlProvider.class, method = "delete")
//    int delete(@Param("tableName") String tableName,@Param("whereCase") Map<String, Object> whereCase);

    @SelectProvider(type = BaseSqlProvider.class, method = "selectAll")
    List<Map<String, Object>> selectAll(String tableName);

    @DeleteProvider(type = BaseSqlProvider.class, method = "deleteByIds")
    int deleteByIdList(@Param("tableName") String tableName, @Param("list") List<?> ids);

    @DeleteProvider(type = BaseSqlProvider.class, method = "deleteAll")
    int deleteAll(String tableName);

    @DeleteProvider(type = BaseSqlProvider.class, method = "deleteByWhereCase")
    int deleteByWhereCase(@Param("tableName") String tableName, @Param("whereCase") String whereCase);

    @InsertProvider(type = BaseSqlProvider.class, method = "insertBatch")
    Integer insertBatch(@Param("tableName") String tableName, @Param("list") List<?> list);

    class BeanCovert
    {
        public static <T> List<T> mapToClassBean(List<Map<String, Object>> mapList, Class<T> clazz)
        {
            if (mapList == null || mapList.isEmpty())
            {
                return Collections.emptyList();
            }

            return mapList
                    .stream()
                    .map(map -> mapToClassBean(map, clazz))
                    .collect(Collectors.toList());
        }

        public static <T> T mapToClassBean(Map<String, Object> map, Class<T> clazz)
        {
            Field[] fields = clazz.getDeclaredFields();
            if (fields.length == 0)
            {
                return null;
            }

            Object o = null;
            try
            {
                o = clazz.newInstance();
            } catch (InstantiationException | IllegalAccessException e)
            {
                e.printStackTrace();
            }

            if (o == null)
            {
                return null;
            }

            for (Field field : fields)
            {
                boolean fieldHasAnno = field.isAnnotationPresent(Column.class);
                if (fieldHasAnno)
                {
                    Column column = field.getAnnotation(Column.class);
                    String colName = column.name();
                    if (StringUtils.isEmpty(colName))
                    {
                        continue;
                    }
                    Object value = map.get(colName);
                    if (value == null)
                    {
                        continue;
                    }

                    String methodName = "set" + toUpperCaseFirstOne(field.getName());
                    try
                    {
                        Method declaredMethod = clazz.getDeclaredMethod(methodName, field.getType());
                        declaredMethod.setAccessible(true);
                        declaredMethod.invoke(o, value);
                    } catch (NoSuchMethodException | IllegalAccessException | InvocationTargetException e)
                    {
                        e.printStackTrace();
                    }
                }
            }
            return clazz.cast(o);
        }

        private static String toUpperCaseFirstOne(String s)
        {
            if (Character.isUpperCase(s.charAt(0)))
            {
                return s;
            }
            else
            {
                return Character.toUpperCase(s.charAt(0)) + s.substring(1);
            }
        }
    }
}
